package com.xdl.modules.system.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xdl.common.constants.CommonConstants;
import com.xdl.common.constants.ResponseStatus;
import com.xdl.common.exception.BelugaException;
import com.xdl.common.response.ResponseCollection;
import com.xdl.common.response.ResponseResult;
import com.xdl.common.utils.MD5Utils;
import com.xdl.common.utils.StringUtils;
import com.xdl.configuration.BaseContextHandler;
import com.xdl.constant.RoleIndexConfigEnum;
import com.xdl.modules.system.entity.SysDepartPermission;
import com.xdl.modules.system.entity.SysPermission;
import com.xdl.modules.system.entity.SysRolePermission;
import com.xdl.modules.system.model.SysPermissionTree;
import com.xdl.modules.system.model.TreeModel;
import com.xdl.modules.system.service.SysDepartPermissionService;
import com.xdl.modules.system.service.SysPermissionService;
import com.xdl.modules.system.service.SysRolePermissionService;
import com.xdl.modules.system.service.SysUserService;
import com.xdl.modules.utils.PermissionDataUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/sys/permission")
@Slf4j
public class SysPermissionController {

    @Autowired
    private SysPermissionService sysPermissionService;

    @Autowired
    private SysDepartPermissionService sysDepartPermissionService;

    @Autowired
    private SysRolePermissionService rolePermissionService;

    @Autowired
    private SysUserService sysUserService;


    /**
     * 加载数据节点
     *
     * @return
     */
    @GetMapping("/list")
    public ResponseCollection<SysPermissionTree> list() {
        long start = System.currentTimeMillis();
        LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<SysPermission>();
        query.eq(SysPermission::getDelFlag, CommonConstants.DEL_FLAG_0);
        query.orderByAsc(SysPermission::getSortNo);
        List<SysPermission> list = sysPermissionService.list(query);
        List<SysPermissionTree> treeList = new ArrayList<>();
        getTreeList(treeList, list, null);
        log.info("======获取全部菜单数据=====耗时:" + (System.currentTimeMillis() - start) + "毫秒");
        return ResponseCollection.Success(treeList);
    }


    /**
     * 获取全部的权限树
     *
     * @return
     */
    @RequestMapping(value = "/queryTreeList", method = RequestMethod.GET)
    public ResponseResult<Map<String, Object>> queryTreeList() {
        // 全部权限ids
        List<String> ids = new ArrayList<>();
        LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<SysPermission>();
        query.eq(SysPermission::getDelFlag, CommonConstants.DEL_FLAG_0);
        query.orderByAsc(SysPermission::getSortNo);
        List<SysPermission> list = sysPermissionService.list(query);
        for (SysPermission sysPer : list) {
            ids.add(sysPer.getId());
        }
        List<TreeModel> treeList = new ArrayList<>();
        getTreeModelList(treeList, list, null);
        Map<String, Object> resMap = new HashMap<String, Object>();
        resMap.put("treeList", treeList); // 全部树节点数据
        resMap.put("ids", ids);// 全部树ids
        return ResponseResult.Success(resMap);
    }


    /**
     * 编辑菜单
     *
     * @param permission
     * @return
     */
    @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
    public ResponseResult<Boolean> edit(@RequestBody SysPermission permission) {
        permission = PermissionDataUtil.intelligentProcessData(permission);
        boolean edit = sysPermissionService.editPermission(permission);
        return ResponseResult.Success();
    }


    /**
     * 添加菜单
     *
     * @param permission
     * @return
     */
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public ResponseResult<Boolean> add(@RequestBody SysPermission permission) {
        permission = PermissionDataUtil.intelligentProcessData(permission);
        boolean add = sysPermissionService.addPermission(permission);
        return ResponseResult.Success(add);
    }


    /**
     * 部门权限表
     *
     * @param departId
     * @return
     */
    @GetMapping("/queryDepartPermission")
    public ResponseCollection<String> queryDepartPermission(@RequestParam(name = "departId", required = true) String departId) {
        List<SysDepartPermission> list = sysDepartPermissionService.list(new QueryWrapper<SysDepartPermission>().lambda().eq(SysDepartPermission::getDepartId, departId));
        List<String> result = list.stream().map(SysDepartPermission -> String.valueOf(SysDepartPermission.getPermissionId())).collect(Collectors.toList());
        return ResponseCollection.Success(result);
    }

    /**
     * 保存部门授权
     *
     * @return
     */
    @PostMapping("/saveDepartPermission")
    public ResponseResult<String> saveDepartPermission(@RequestBody JSONObject json) {
        String departId = json.getString("departId");
        String permissionIds = json.getString("permissionIds");
        String lastPermissionIds = json.getString("lastpermissionIds");
        this.sysDepartPermissionService.saveDepartPermission(departId, permissionIds, lastPermissionIds);
        return ResponseResult.Success();
    }

    /**
     * 删除菜单
     *
     * @param id
     * @return
     */
    @DeleteMapping("/delete")
    public ResponseResult<Boolean> delete(@RequestParam(name = "id", required = true) String id) {
        Boolean delete = sysPermissionService.deletePermission(id);
        return ResponseResult.Success(delete);
    }


    /**
     * 批量删除菜单
     *
     * @param ids
     * @return
     */
    @RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
    public ResponseResult<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
        String[] arr = ids.split(",");
        for (String id : arr) {
            if (StringUtils.isNotEmpty(id)) {
                sysPermissionService.deletePermission(id);
            }
        }
        return ResponseResult.Success("删除成功！");
    }

    /**
     * 查询角色授权
     *
     * @return
     */
    @GetMapping("/queryRolePermission")
    public ResponseCollection<String> queryRolePermission(@RequestParam(name = "roleId", required = true) String roleId) {
        List<SysRolePermission> list = rolePermissionService.list(new QueryWrapper<SysRolePermission>().lambda().eq(SysRolePermission::getRoleId, roleId));
        List<String> result = list.stream().map(SysRolePermission -> String.valueOf(SysRolePermission.getPermissionId())).collect(Collectors.toList());
        return ResponseCollection.Success(result);
    }

    /**
     * 保存角色授权
     *
     * @return
     */
    @RequestMapping(value = "/saveRolePermission", method = RequestMethod.POST)
    public ResponseResult<String> saveRolePermission(@RequestBody JSONObject json) {
        long start = System.currentTimeMillis();
        String roleId = json.getString("roleId");
        String permissionIds = json.getString("permissionIds");
        String lastPermissionIds = json.getString("lastpermissionIds");
        boolean save = this.rolePermissionService.saveRolePermission(roleId, permissionIds, lastPermissionIds);
        log.info("======角色授权成功=====耗时:" + (System.currentTimeMillis() - start) + "毫秒");
        return ResponseResult.Success("保存成功！");
    }


    private void getTreeModelList(List<TreeModel> treeList, List<SysPermission> metaList, TreeModel temp) {
        for (SysPermission permission : metaList) {
            String tempPid = permission.getParentId();
            TreeModel tree = new TreeModel(permission);
            if (temp == null && StringUtils.isEmpty(tempPid)) {
                treeList.add(tree);
                if (!tree.getIsLeaf()) {
                    getTreeModelList(treeList, metaList, tree);
                }
            } else if (temp != null && tempPid != null && tempPid.equals(temp.getKey())) {
                temp.getChildren().add(tree);
                if (!tree.getIsLeaf()) {
                    getTreeModelList(treeList, metaList, tree);
                }
            }

        }
    }


    private void getTreeList(List<SysPermissionTree> treeList, List<SysPermission> metaList, SysPermissionTree temp) {
        for (SysPermission permission : metaList) {
            String tempPid = permission.getParentId();
            SysPermissionTree tree = new SysPermissionTree(permission);
            if (temp == null && StringUtils.isEmpty(tempPid)) {
                treeList.add(tree);
                if (!tree.getIsLeaf()) {
                    getTreeList(treeList, metaList, tree);
                }
            } else if (temp != null && tempPid != null && tempPid.equals(temp.getId())) {
                temp.getChildren().add(tree);
                if (!tree.getIsLeaf()) {
                    getTreeList(treeList, metaList, tree);
                }
            }

        }
    }


    /**
     * 查询用户拥有的菜单权限和按钮权限
     *
     * @return
     */
    @GetMapping(value = "/getUserPermissionByToken")
    public ResponseResult<JSONObject> getUserPermissionByToken() {
        String username = BaseContextHandler.getUsername();
        if (StringUtils.isEmpty(username)) {
            BelugaException.fatal(ResponseStatus.CREDENTIALS_EXPIRED);
        }
        List<SysPermission> metaList = sysPermissionService.queryByUser(username);
        if (!PermissionDataUtil.hasIndexPage(metaList)) {
            SysPermission indexMenu = sysPermissionService.list(new LambdaQueryWrapper<SysPermission>().eq(SysPermission::getName, "首页")).get(0);
            metaList.add(0, indexMenu);
        }
        List<String> roles = sysUserService.getRole(username);
        String compUrl = RoleIndexConfigEnum.getIndexByRoles(roles);
        if (org.apache.commons.lang3.StringUtils.isNotBlank(compUrl)) {
            List<SysPermission> menus = metaList.stream().filter(sysPermission -> "首页".equals(sysPermission.getName())).collect(Collectors.toList());
            menus.get(0).setComponent(compUrl);
        }
        JSONObject json = new JSONObject();
        JSONArray menujsonArray = new JSONArray();
        this.getPermissionJsonArray(menujsonArray, metaList, null);
        //一级菜单下的子菜单全部是隐藏路由，则一级菜单不显示
        this.handleFirstLevelMenuHidden(menujsonArray);

        JSONArray authjsonArray = new JSONArray();
        this.getAuthJsonArray(authjsonArray, metaList);
        //查询所有的权限
        LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<SysPermission>();
        query.eq(SysPermission::getDelFlag, CommonConstants.DEL_FLAG_0);
        query.eq(SysPermission::getMenuType, CommonConstants.MENU_TYPE_2);
        //query.eq(SysPermission::getStatus, "1");
        List<SysPermission> allAuthList = sysPermissionService.list(query);
        JSONArray allauthjsonArray = new JSONArray();
        this.getAllAuthJsonArray(allauthjsonArray, allAuthList);
        //路由菜单
        json.put("menu", menujsonArray);
        //按钮权限（用户拥有的权限集合）
        json.put("auth", authjsonArray);
        //全部权限配置集合（按钮权限，访问权限）
        json.put("allAuth", allauthjsonArray);
        json.put("sysSafeMode", false);
        return ResponseResult.Success(json);
    }

    /**
     * 获取权限JSON数组
     *
     * @param jsonArray
     * @param allList
     */
    private void getAllAuthJsonArray(JSONArray jsonArray, List<SysPermission> allList) {
        JSONObject json = null;
        for (SysPermission permission : allList) {
            json = new JSONObject();
            json.put("action", permission.getPerms());
            json.put("status", permission.getStatus());
            //1显示2禁用
            json.put("type", permission.getPermsType());
            json.put("describe", permission.getName());
            jsonArray.add(json);
        }
    }

    /**
     * 获取权限JSON数组
     *
     * @param jsonArray
     * @param metaList
     */
    private void getAuthJsonArray(JSONArray jsonArray, List<SysPermission> metaList) {
        for (SysPermission permission : metaList) {
            if (permission.getMenuType() == null) {
                continue;
            }
            JSONObject json = null;
            if (permission.getMenuType().equals(CommonConstants.MENU_TYPE_2) && CommonConstants.STATUS_1.equals(permission.getStatus())) {
                json = new JSONObject();
                json.put("action", permission.getPerms());
                json.put("type", permission.getPermsType());
                json.put("describe", permission.getName());
                jsonArray.add(json);
            }
        }
    }

    /**
     * 一级菜单的子菜单全部是隐藏路由，则一级菜单不显示
     *
     * @param jsonArray
     */
    private void handleFirstLevelMenuHidden(JSONArray jsonArray) {
        jsonArray = jsonArray.stream().map(obj -> {
            JSONObject returnObj = new JSONObject();
            JSONObject jsonObj = (JSONObject) obj;
            if (jsonObj.containsKey("children")) {
                JSONArray childrens = jsonObj.getJSONArray("children");
                childrens = childrens.stream().filter(arrObj -> !"true".equals(((JSONObject) arrObj).getString("hidden"))).collect(Collectors.toCollection(JSONArray::new));
                if (childrens == null || childrens.size() == 0) {
                    jsonObj.put("hidden", true);

                    //vue3版本兼容代码
                    JSONObject meta = new JSONObject();
                    meta.put("hideMenu", true);
                    jsonObj.put("meta", meta);
                }
            }
            return returnObj;
        }).collect(Collectors.toCollection(JSONArray::new));
    }

    /**
     * 获取菜单JSON数组
     *
     * @param jsonArray
     * @param metaList
     * @param parentJson
     */
    private void getPermissionJsonArray(JSONArray jsonArray, List<SysPermission> metaList, JSONObject parentJson) {
        for (SysPermission permission : metaList) {
            if (permission.getMenuType() == null) {
                continue;
            }
            String tempPid = permission.getParentId();
            JSONObject json = getPermissionJsonObject(permission);
            if (json == null) {
                continue;
            }
            if (parentJson == null && StringUtils.isEmpty(tempPid)) {
                jsonArray.add(json);
                if (!permission.isLeaf()) {
                    getPermissionJsonArray(jsonArray, metaList, json);
                }
            } else if (parentJson != null && StringUtils.isNotEmpty(tempPid) && tempPid.equals(parentJson.getString("id"))) {
                // 类型( 0：一级菜单 1：子菜单 2：按钮 )
                if (permission.getMenuType().equals(CommonConstants.MENU_TYPE_2)) {
                    JSONObject metaJson = parentJson.getJSONObject("meta");
                    if (metaJson.containsKey("permissionList")) {
                        metaJson.getJSONArray("permissionList").add(json);
                    } else {
                        JSONArray permissionList = new JSONArray();
                        permissionList.add(json);
                        metaJson.put("permissionList", permissionList);
                    }
                    // 类型( 0：一级菜单 1：子菜单 2：按钮 )
                } else if (permission.getMenuType().equals(CommonConstants.MENU_TYPE_1) || permission.getMenuType().equals(CommonConstants.MENU_TYPE_0)) {
                    if (parentJson.containsKey("children")) {
                        parentJson.getJSONArray("children").add(json);
                    } else {
                        JSONArray children = new JSONArray();
                        children.add(json);
                        parentJson.put("children", children);
                    }
                    if (!permission.isLeaf()) {
                        getPermissionJsonArray(jsonArray, metaList, json);
                    }
                }
            }

        }
    }

    /**
     * 根据菜单配置生成路由json
     *
     * @param permission
     * @return
     */
    private JSONObject getPermissionJsonObject(SysPermission permission) {
        JSONObject json = new JSONObject();
        // 类型(0：一级菜单 1：子菜单 2：按钮)
        if (permission.getMenuType().equals(CommonConstants.MENU_TYPE_2)) {
            return null;
        } else if (permission.getMenuType().equals(CommonConstants.MENU_TYPE_0) || permission.getMenuType().equals(CommonConstants.MENU_TYPE_1)) {
            json.put("id", permission.getId());
            if (permission.isRoute()) {
                json.put("route", "1");// 表示生成路由
            } else {
                json.put("route", "0");// 表示不生成路由
            }

            if (isWWWHttpUrl(permission.getUrl())) {
                json.put("path", MD5Utils.MD5Encode(permission.getUrl(), "utf-8"));
            } else {
                json.put("path", permission.getUrl());
            }

            // 重要规则：路由name (通过URL生成路由name,路由name供前端开发，页面跳转使用)
            if (StringUtils.isNotEmpty(permission.getComponentName())) {
                json.put("name", permission.getComponentName());
            } else {
                json.put("name", urlToRouteName(permission.getUrl()));
            }

            JSONObject meta = new JSONObject();
            // 是否隐藏路由，默认都是显示的
            if (StringUtils.isNotEmpty(permission.isHidden()) && permission.isHidden()) {
                json.put("hidden", true);
                //vue3版本兼容代码
                meta.put("hideMenu", true);
            }
            // 聚合路由
            if (StringUtils.isNotEmpty(permission.isAlwaysShow()) && permission.isAlwaysShow()) {
                json.put("alwaysShow", true);
            }
            json.put("component", permission.getComponent());
            // 由用户设置是否缓存页面 用布尔值
            if (StringUtils.isNotEmpty(permission.isKeepAlive()) && permission.isKeepAlive()) {
                meta.put("keepAlive", true);
            } else {
                meta.put("keepAlive", false);
            }
            //外链菜单打开方式
            if (StringUtils.isNotEmpty(permission.isInternalOrExternal()) && permission.isInternalOrExternal()) {
                meta.put("internalOrExternal", true);
            } else {
                meta.put("internalOrExternal", false);
            }
            meta.put("title", permission.getName());
            String component = permission.getComponent();
            if (StringUtils.isNotEmpty(permission.getComponentName()) || StringUtils.isNotEmpty(component)) {
                meta.put("componentName", StringUtils.getString(permission.getComponentName(), component.substring(component.lastIndexOf("/") + 1)));
            }
            if (StringUtils.isEmpty(permission.getParentId())) {
                // 一级菜单跳转地址
                json.put("redirect", permission.getRedirect());
                if (StringUtils.isNotEmpty(permission.getIcon())) {
                    meta.put("icon", permission.getIcon());
                }
            } else {
                if (StringUtils.isNotEmpty(permission.getIcon())) {
                    meta.put("icon", permission.getIcon());
                }
            }
            if (isWWWHttpUrl(permission.getUrl())) {
                meta.put("url", permission.getUrl());
            }
            if (StringUtils.isNotEmpty(permission.isHideTab()) && permission.isHideTab()) {
                meta.put("hideTab", true);
            }
            json.put("meta", meta);
        }

        return json;
    }

    /**
     * 判断是否外网URL 例如： http://localhost:8080/jeecg-boot/swagger-ui.html#/ 支持特殊格式： {{
     * window._CONFIG['domianURL'] }}/druid/ {{ JS代码片段 }}，前台解析会自动执行JS代码片段
     *
     * @return
     */
    private boolean isWWWHttpUrl(String url) {
        if (url != null && (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("{{"))) {
            return true;
        }
        return false;
    }

    /**
     * 通过URL生成路由name（去掉URL前缀斜杠，替换内容中的斜杠‘/’为-） 举例： URL = /isystem/role RouteName =
     * isystem-role
     *
     * @return
     */
    private String urlToRouteName(String url) {
        if (StringUtils.isNotEmpty(url)) {
            if (url.startsWith("/")) {
                url = url.substring(1);
            }
            url = url.replace("/", "-");

            // 特殊标记
            url = url.replace(":", "@");
            return url;
        } else {
            return null;
        }
    }

}
